/**
 * Copyright 2018-2020 witer & itdever (itdever@qq.com)
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.ruoyi.common.utils.file;

import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.file.FileException;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Base64;

/**
 * NIO方式读取文件
 *
 * @author surfman
 * @Date 2018/1/4 23:09
 */
public class FileUtil {

    private static Logger log = LoggerFactory.getLogger(FileUtil.class);

    public static byte[] toByteArray(String filename) {

        File f = new File(filename);
        if (!f.exists()) {
            log.error("文件{}未找到！", filename);
            throw new ServiceException("文件未找到！");
        }
        FileChannel channel = null;
        FileInputStream fs = null;
        try {
            fs = new FileInputStream(f);
            channel = fs.getChannel();
            ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size());
            return byteBuffer.array();
        } catch (IOException e) {
            throw new FileException("文件读取错误！");
        } finally {
            try {
                channel.close();
            } catch (IOException e) {
                throw new FileException("文件读取错误！");
            }
            try {
                fs.close();
            } catch (IOException e) {
                throw new FileException("文件读取错误！");
            }
        }
    }

    /**
     * 获取文件扩展名（返回小写）
     *
     * @param fileName
     * @return
     */
    public static String getFileExtension(String fileName) {
        if ((fileName == null) || (fileName.lastIndexOf(".") == -1)
                || (fileName.lastIndexOf(".") == fileName.length() - 1)
        ) {
            return null;
        }
        return fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
    }

    /**
     * 保存文件
     *
     * @param multipartFile
     * @param path
     * @param fileName
     * @return
     */
    public static String saveFile(MultipartFile multipartFile, String path, String fileName) throws IOException {
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }
        FileInputStream inputStream = (FileInputStream) multipartFile.getInputStream();
        return saveFile(inputStream, path, fileName);
    }

    public static String saveFile(ByteArrayInputStream fileInputStream, String path, String fileName) throws IOException {
        String filePath = path + File.separator + fileName;
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
        byte[] bs = new byte[1024];
        int len;
        while ((len = fileInputStream.read(bs)) != -1) {
            bos.write(bs, 0, len);
        }
        bos.flush();
        bos.close();
        return filePath;
    }

    public static String saveFile(FileInputStream fileInputStream, String path, String fileName) throws IOException {
        String filePath = path + File.separator + fileName;
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
        byte[] bs = new byte[1024];
        int len;
        while ((len = fileInputStream.read(bs)) != -1) {
            bos.write(bs, 0, len);
        }
        bos.flush();
        bos.close();
        return filePath;
    }

    public static String saveFile(byte[] bytes, String path, String fileName) throws IOException {
        String filePath = path + File.separator + fileName;
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
        bos.write(bytes);
        bos.flush();
        bos.close();
        return filePath;
    }

    /**
     * 删除文件
     * @param fileName
     * @return
     */
    public static boolean deleteFile(String fileName){
        File file = new File(fileName);
        if(file.exists() && file.isFile()){
            if(file.delete()){
                log.info("删除文件 {} 成功", fileName);
                return true;
            }else {
                log.info("删除文件 {} 失败", fileName);
                return false;
            }
        }else {
            log.info("删除文件 {} 失败, {} 不存在", fileName, fileName);
            return false;
        }
    }

    /**
     * 根据文件地址读取文件字节
     * @param filePath
     * @return
     * @throws IOException
     */
    public static  byte[] readFileByBytes(String filePath) throws IOException{
        File file = new File(filePath);
        if(!file.exists()){
            throw new FileException("找不到文件！");
        }else {
            try (ByteArrayOutputStream bos = new ByteArrayOutputStream((int)file.length())){
                try(BufferedInputStream in = new BufferedInputStream(new FileInputStream(file))){
                    int buSize = 1024;
                    byte[] buffer = new byte[buSize];
                    int len;
                    while ((len = in.read(buffer, 0, buSize)) != -1){
                        bos.write(buffer, 0 , len);
                    }
                    return bos.toByteArray();
                }
            }
        }
    }

    public static void downLoadFile(String filePath, boolean notIe, HttpServletResponse response){
        File file = new File(filePath);
        if(file.exists()){
            FileInputStream fis = null;
            BufferedInputStream bis = null;
            OutputStream os = null;
            try {
                os = response.getOutputStream();
                fis = new FileInputStream(file);
                bis = new BufferedInputStream(fis);
                byte [] buff = new byte[bis.available() + 1000];
                int i = bis.read(buff);
                while (i != -1){
                    os.write(buff, 0 , i);
                    os.flush();
                    i = bis.read(buff);
                }
                response.setHeader("Content-Lenth", String.valueOf(fis.available()));
            } catch (FileNotFoundException e1){
                throw new FileException("文件未找到");
            } catch (IOException e){
                log.error(e.getMessage());
                throw new FileException("文件下载失败");
            } finally {
                if(bis != null){
                    try {
                        bis.close();
                    } catch (IOException e){
                        log.error(e.getMessage());
                        throw new FileException("文件下载失败");
                    }
                }
                if(fis != null){
                    try {
                        fis.close();
                    } catch (IOException e){
                        log.error(e.getMessage());
                        throw new FileException("文件下载错误");
                    }
                }
            }
        }else {
            throw new FileException("文件未找到");
        }
    }

    public static byte[] getFile(String filePath, boolean notIe){
        File file = new File(filePath);
        if(file.exists()){
            byte[] buffer = null;
            try
            {
                FileInputStream fis = new FileInputStream(file);
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                byte[] b = new byte[1024];
                int n;
                while ((n = fis.read(b)) != -1)
                {
                    bos.write(b, 0, n);
                }
                fis.close();
                bos.close();
                buffer = bos.toByteArray();
            }catch (FileNotFoundException e){
                e.printStackTrace();
            }catch (IOException e){
                e.printStackTrace();
            }
            return buffer;
        }else {
            throw new FileException("文件未找到");
        }
    }

    /**
     * 说明：根据指定URL将文件下载到指置定目标位置
     *
     * @param urlPath 下载路径
     * @param fileName 文件存放目录
     * @param notIe 文件存放目录
     * @param response 文件存放目录
     * @return 返回下载文件
     */
    @SuppressWarnings("finally")
    public static void downLoadUrl(String urlPath, String fileName, boolean notIe, HttpServletResponse response) {
        BufferedInputStream bin = null;
        OutputStream os = null;
        try {
            URL url = new URL(urlPath);
            InputStream is = url.openStream();
            bin = new BufferedInputStream(is);
            try {
                response.setHeader("content-type", "application/octet-stream");
                response.setContentType("application/octet-stream");
                response.setHeader("Content-Lenth", String.valueOf(is.available()));
                String name = java.net.URLEncoder.encode(fileName, "UTF-8");
                if(notIe){
                    name = java.net.URLEncoder.encode(fileName, "ISO-8859-1");
                }
                response.setHeader("Content-Disposition", "attachment;filename=" + name);
            } catch (UnsupportedEncodingException e2){
                log.error(e2.getMessage());
                throw new FileException("文件下载失败");
            }
            os = response.getOutputStream();
            int size = 0;
//            int len = 0;
            byte[] buf = new byte[2048];
            while ((size = bin.read(buf)) != -1) {
//                len += size;
                os.write(buf, 0, size);
                // 控制台打印文件下载的百分比情况
                // System.out.println("下载了-------> " + len * 100 / fileLength + "%\n");
            }
        } catch (IOException e){
            log.error(e.getMessage());
            throw new FileException("文件下载失败");
        } finally {
            if(bin != null){
                try {
                    bin.close();
                } catch (IOException e){
                    log.error(e.getMessage());
                    throw new FileException("文件下载失败");
                }
            }
            if(os != null){
                try {
                    os.close();
                } catch (IOException e){
                    log.error(e.getMessage());
                    throw new FileException("文件下载失败");
                }
            }
        }

    }

    public static void  inputStream2File(InputStream is, File file) throws IOException {
        OutputStream os = null;
        try {
            os = new FileOutputStream(file);
            int len = 0;
            byte[] buffer = new byte[8192];
            while ((len = is.read(buffer)) != -1){
                os.write(buffer, 0, len);
            }
        } finally {
            os.close();
            is.close();
        }

    }

    public static MultipartFile fileToMultipartFile(File file) {
        FileItem fileItem = createFileItem(file);
        MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
        return multipartFile;
    }

    private static FileItem createFileItem(File file) {
        FileItemFactory factory = new DiskFileItemFactory(16, null);
        FileItem item = factory.createItem("textField", "text/plain", true, file.getName());
        int bytesRead = 0;
        byte[] buffer = new byte[8192];
        try {
            FileInputStream fis = new FileInputStream(file);
            OutputStream os = item.getOutputStream();
            while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return item;
    }

    /**
     * 按照文件地址写入本地
     * @param: filePath
     * @return: void
     */
    public static void writeBytesLocal(String filePath, OutputStream os) throws IOException {
        FileInputStream fis = null;
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                throw new FileNotFoundException(filePath);
            }
            fis = new FileInputStream(file);
            byte[] b = new byte[1024];
            int length;
            while ((length = fis.read(b)) > 0) {
                os.write(b, 0, length);
            }
        } catch (IOException e) {
            throw e;
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    /**
     * 按照文件地址写入本地
     * @param: filePath
     * @return: void
     */
    public static void writeByteLocal(String filePath, byte[] bs) throws IOException {
        File file = new File(filePath);
        file.getParentFile().mkdirs();
        file.createNewFile();
        OutputStream out = new FileOutputStream(filePath);
        InputStream is = new ByteArrayInputStream(bs);
        byte[] buff = new byte[1024];
        int len = 0;
        while((len=is.read(buff))!=-1){
            out.write(buff, 0, len);
        }
        is.close();
        out.close();
    }

    /**
     * 按照文件地址写入本地
     * @param: filePath
     * @return: void
     */
    public static void writeBytes(String filePath, OutputStream os) throws IOException {
        FileInputStream fis = null;
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                throw new FileNotFoundException(filePath);
            }
            fis = new FileInputStream(file);
            byte[] b = new byte[1024];
            int length;
            while ((length = fis.read(b)) > 0) {
                os.write(b, 0, length);
            }
        } catch (IOException e) {
            throw e;
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    public static byte[] base64StrToByte(String base64Str) {
        byte[] bytes = Base64.getDecoder().decode(base64Str);
        for (int i = 0; i < bytes.length; ++i) {
            if (bytes[i] < 0) {// 调整异常数据
                bytes[i] += 256;
            }
        }
        return bytes;
    }

    public static FileItem createFileItem(byte[] bytes) {
        FileItemFactory factory = new DiskFileItemFactory(16, null);
        FileItem item = factory.createItem("textField", "text/plain", true, "测试文件.jpg");
        int bytesRead = 0;
        try {
            OutputStream os = item.getOutputStream();
            os.write(bytes, 0, bytes.length);
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return item;
    }

}